查看原文
其他

完全由C编写,高度可移植,超级牛逼的软件定时器!

晓宇 芯片之家 2021-01-31

作为一个搞电子嵌入式的你来说,定时器相信绝对不会陌生,去翻看STM32的官方数据手册,可能有四分之一的篇幅都在讲定时器,可见定时器的重要性,定时器定时器嘛,最重要的功能还是定时。之前经常有师弟跟我抱怨,哎呀,这个单片机怎么只有2个定时器,我都不够用了,怎么办呀,然后一头雾水,其实,只要有一个硬件定时器,在实际不是要求特别特别精准的场合,我们可以模拟很多个软件定时器出来,今天,群主给大家分享一个完全由C语言编写,高度可移植,超级牛逼的软件定时器!


MultiTimer 是一个软件定时器扩展模块,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。一共有3个文件:

multi_timer.c--定时器c源文件;
multi_timer.h--定时器h头文件;
main--用户代码文件。


我们直接上代码:

/*
*     main.c
*
*      Created on: 20161229
*      @Author   : 晓宇 <karaxiaoyu@gmail.com>
*      @version  :V1.0.0
*
*                        ,%%%%%%%%,
*                      ,%%/\%%%%/\%%
*                     ,%%%\c''''J/%%%
*           %.        %%%%/ o  o \%%%
*           `%%.      %%%%       |%%%
*            `%%      `%%%%(__Y__)%%'
*            //        ;%%%%`\-/%%%'
*            ((      /   `%%%%%%%'
*             \\     .'           |
*              \\   /        \  | |
*               \\/          ) | |
*                \          /_ | |__
*                (____________))))))) 攻城狮
*
*/


#include "multi_timer.h"

struct Timer timer1;
struct Timer timer2;

void timer1_callback()
{
   printf("timer1 timeout!\r\n");
}

void timer2_callback()
{
   printf("timer2 timeout!\r\n");
}

int main()
{
 timer_init(&timer1, timer1_callback, 1000, 1000); //1s loop
 timer_start(&timer1);
 
 timer_init(&timer2, timer2_callback, 50, 0); //50ms delay
 timer_start(&timer2);
 
 while(1) {
     
     timer_loop();
 }
}

void HAL_SYSTICK_Callback(void)
{
   timer_ticks(); //1ms ticks
}


1、先申请一个定时器管理handle

```
struct Timer timer1;
`
``

2、初始化定时器对象,注册定时器回调处理函数,设置定时时间(ms),循环定时触发时间

```
timer_init(struct Timer* handle, void(*timeout_cb)(), uint32_t timeout, uint32_t repeat);
`
``

3.启动定时器

```
timer_start(&timer1);
`
``

4.设置1ms的硬件定时器循环调用 *timer_ticks()* 以提供时间基准

```
void HAL_SYSTICK_Callback(void)
{
   timer_ticks();
}
`
``

5.在主循环调用定时器后台处理函数

```
int main()
{    ...
   while(1) {
       ...
       timer_loop();
   }
}
`
``


上面,我们定义了两个定时器,第一个以每1秒一次进行循环执行,第二个定时器50ms之后只执行一次,执行之后,可以通过相应的回调函数打印出来,里面就可以添加我们的定时任务了。怎么样,是不是很简单,只需要设置好定时基准,申请好定时器,初始化完毕,你想要的效果,是定时一次还是进行循环,都没问题,多个定时器之间使用链表来实现,可以启动暂停每个定时器,用起来之后,是不是很爽?具体的代码,需要大家仔细去推敲其中的原理,当然直接用也是可以的,具体源代码,我会上传到百度云,公众号后台,注意是后台,回复软件定时器下载源文件,觉得好的,欢迎进行转发,算是对群主的支持,谢谢!


部分源代码展示:

/*
*     multi_timer.h
*
*      Created on: 20161229
*      @Author   : 晓宇 <karaxiaoyu@gmail.com>  
*      @version  :V1.0.0
*/


#ifndef _MULTI_TIMER_H_
#define _MULTI_TIMER_H_

#include "stdint.h"

typedef struct Timer {
   uint32_t timeout;
   uint32_t repeat;
   void (*timeout_cb)(void);
   struct Timer* next;
}Timer;

#ifdef __cplusplus  
extern "C" {  
#endif  

void timer_init(struct Timer* handle, void(*timeout_cb)(), uint32_t timeout, uint32_t repeat);
int  timer_start(struct Timer* handle);
void timer_stop(struct Timer* handle);
void timer_ticks(void);
void timer_loop(void);

// void timer_again(struct Timer* handle);
// void timer_set_repeat(struct Timer* handle, uint32_t repeat);

#ifdef __cplusplus
}
#endif

#endif
/*
*     multi_timer.c
*
*      Created on: 20161229
*      @Author   : 晓宇 <karaxiaoyu@gmail.com>  
*      @version  :V1.0.0
*/



#include "multi_timer.h"

//timer handle list head.
static struct Timer* head_handle = NULL;

//Timer ticks
static uint32_t _timer_ticks = 0;

/**
 * @brief  Initializes the timer struct handle.
 * @param  handle: the timer handle strcut.
 * @param  timeout_cb: timeout callback.
 * @param  repeat: repeat interval time.
 * @retval None
 */

void timer_init(struct Timer* handle, void(*timeout_cb)(), uint32_t timeout, uint32_t repeat)
{
 // memset(handle, sizeof(struct Timer), 0);
 handle->timeout_cb = timeout_cb;
 handle->timeout = _timer_ticks + timeout;
 handle->repeat = repeat;
}

/**
 * @brief  Start the timer work, add the handle into work list.
 * @param  btn: target handle strcut.
 * @retval 0: succeed. -1: already exist.
 */

int timer_start(struct Timer* handle)
{
 struct Timer* target = head_handle;
 while(target) {
   if(target == handle) return -1;  //already exist.
   target = target->next;
 }
 handle->next = head_handle;
 head_handle = handle;
 return 0;
}

/**
 * @brief  Stop the timer work, remove the handle off work list.
 * @param  handle: target handle strcut.
 * @retval None
 */

void timer_stop(struct Timer* handle)
{
 struct Timer** curr;
 for(curr = &head_handle; *curr; ) {
   struct Timer* entry = *curr;
   if (entry == handle) {
     *curr = entry->next;
//      free(entry);
   } else
     curr = &entry->next;
 }
}

/**
 * @brief  main loop.
 * @param  None.
 * @retval None
 */

void timer_loop()
{
 struct Timer* target;
 for(target=head_handle; target; target=target->next) {
   if(_timer_ticks >= target->timeout) {
     if(target->repeat == 0) {
       timer_stop(target);
     } else {
       target->timeout = _timer_ticks + target->repeat;
     }
     target->timeout_cb();
   }
 }
}

/**
 * @brief  background ticks, timer repeat invoking interval 1ms.
 * @param  None.
 * @retval None.
 */

void timer_ticks()
{
 _timer_ticks++;
}


往期好文


【拆解】小米AI音箱,看看小爱同学内部究竟有什么


【拆解】斐讯AI智能音箱R1,内部究竟采用了什么?


【视频】老外教你学电子系列第13期-第15期,我就不信还有不懂的!


【最强干货】618个3D封装免费分享


Google Home拆解,看看这个神秘的设备里面到底有什么?


阿里巴巴人工智能实验室2018春季发布会完整版视频


MPS软件帮您搞定DC-DC电源设计!


天呐!身为电子工程师的你,竟然还在用百度找资料?


茸茸大神带你玩跨界,“泛读”“精读”两大神器助你阅读datasheet

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存